package com.topisv.tms.service.md;

import java.io.ByteArrayOutputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.bind.JAXB;

import org.apache.http.client.fluent.Request;
import org.apache.http.client.fluent.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//import org.fusesource.hawtbuf.ByteArrayOutputStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.topisv.tms.entity.CheckInOrOut;
import com.topisv.tms.entity.CheckInOrOutItem;
import com.topisv.tms.entity.EdiGoodsSku;
import com.topisv.tms.entity.stock.reverse.ReverseBill;
import com.topisv.tms.entity.stock.reverse.ReverseBillItem;
import com.topisv.tms.exception.ErrorCode;
import com.topisv.tms.exception.PaiUException;
import com.topisv.tms.repository.EdiGoodsSkuDao;
import com.topisv.tms.repository.md.MDCheckInOrOutDao;
import com.topisv.tms.repository.md.MDCheckInOrOutItemDao;
import com.topisv.tms.repository.stock.reverse.ReverseBillDao;
import com.topisv.tms.repository.stock.reverse.ReverseBillItemDao;
import com.topisv.tms.rest.entity.md.request.OrderConfirmDetail;
import com.topisv.tms.rest.entity.md.request.OrderConfirmRequestBody;
import com.topisv.tms.rest.entity.md.request.TransferBody;
import com.topisv.tms.rest.entity.md.request.TransferData;
import com.topisv.tms.rest.entity.md.request.TransferSubject;
import com.topisv.tms.service.base.BaseService;
import com.topisv.tms.service.vo.invoice.MDParam;
import com.topisv.tms.utils.SystemUtil;
import com.topisv.tms.utils.enums.MDDocumentType;
import com.topisv.tms.utils.enums.MDOrderType;
import com.topisv.tms.utils.rule.TMSTransportRule;

@Component
public class MDCheckInOrOutService extends BaseService {
	
	private static final Logger log = LoggerFactory.getLogger(MDCheckInOrOutService.class);
	
	@Autowired
	private MDCheckInOrOutDao mdCheckInOrOutDao;
	@Autowired
	private MDCheckInOrOutItemDao mdCheckInOrOutItemDao;
	@Autowired
	private ReverseBillDao reverseBillDao;
	@Autowired
	private ReverseBillItemDao reverseBillItemDao;
	@Autowired
	private EdiGoodsSkuDao ediGoodsSkuDao;
	
	public void saveCheckInOrOut4MD(CheckInOrOut checkInOrOut) {
		log.info("美的盘点出入库消息接收：start，");
		Map<String,EdiGoodsSku> cacheSku = new HashMap<String,EdiGoodsSku>();
		
		ReverseBill reverseBill = new ReverseBill();
		reverseBill.setBillCode(TMSTransportRule.generateReverseBillCode());
		reverseBill.setBillType("check");
		reverseBill.setCreaterUuid("ADMIN");
		reverseBill.setCreateTime(new Date());
		reverseBill.setAboutCode(checkInOrOut.getMdOrderNo());
		reverseBill.setCustomerCode(checkInOrOut.getCustCustomerCode());
		reverseBill.setWarehouseCode(checkInOrOut.getWarehouseCode());
		reverseBill.setStatus("undo");
		reverseBill.setIsAllocated("N");
		log.info("美的盘点出入库消息接收：先添加一个冲正管理记录，");
		reverseBillDao.save(reverseBill);
		
		List<ReverseBillItem> itemList = new ArrayList<ReverseBillItem>();
		for(CheckInOrOutItem ciooi:checkInOrOut.getItemList()){
			//设置冲正编号
			ciooi.setBillCode(reverseBill.getBillCode());
			
			EdiGoodsSku ediGoodsSku = getEdiGoodsBar(reverseBill.getCustomerCode(), ciooi.getCustGoodsCode(), cacheSku);
			ReverseBillItem billItem = new ReverseBillItem();
			billItem.setBillCode(reverseBill.getBillCode());
//			billItem.setBoxCode();
			billItem.setCustomerCode(reverseBill.getCustomerCode());
			billItem.setOrderNumFix(0);
			
			if("normal".equals(ciooi.getGoodsStatus())){
				if(MDOrderType.CHECKIN.getType().equals(checkInOrOut.getOrderType())){
					billItem.setSalesNumFix(ciooi.getPlanQty());
				}else if(MDOrderType.CHECKOUT.getType().equals(checkInOrOut.getOrderType())) {
					billItem.setSalesNumFix(ciooi.getPlanQty()*-1);
				}
				billItem.setUnusedNumFix(0);
			}else {
				if(MDOrderType.CHECKIN.getType().equals(checkInOrOut.getOrderType())){
					billItem.setUnusedNumFix(ciooi.getPlanQty());
				}else if(MDOrderType.CHECKOUT.getType().equals(checkInOrOut.getOrderType())) {
					billItem.setUnusedNumFix(ciooi.getPlanQty()*-1);
				}
				billItem.setSalesNumFix(0);
			}
				
			billItem.setSku(ediGoodsSku.getSku());
			billItem.setStatus("undo");
//			billItem.setStockCode();
			
			billItem.setWarehouseCode(reverseBill.getWarehouseCode());
			itemList.add(billItem);
		}
		log.info("美的盘点出入库消息接收：再先添加一个冲正管理记录，");
		this.reverseBillItemDao.save(itemList);
		
		
		
		checkInOrOut.setBillCode(reverseBill.getBillCode());
		checkInOrOut.setStatus("new");
		log.info("美的盘点出入库消息接收：插入盘点出入库表，");
		mdCheckInOrOutDao.save(checkInOrOut);
		log.info("美的盘点出入库消息接收：插入盘点出入库明细表，");
		mdCheckInOrOutItemDao.save(checkInOrOut.getItemList());
		
		log.info("美的盘点出入库消息接收：end，");
	}
	
	public void sendMDCheckInOrOut(String billCode) throws Exception {
		log.info("美的盘点出入库反馈：start，");
		TransferData transferData = new TransferData(); 
		TransferSubject transferSubject = new TransferSubject();
		transferSubject.setSender("PaiUEB");
		transferSubject.setReceiver("AnntoOMS");
		transferSubject.setDataGenerationTime(new Date());
		transferSubject.setTransferFileID(TMSTransportRule.generateByPreFix("CIO"));
		transferSubject.setDocumentType(MDDocumentType.ORDERCONFIM.getSubjectType());
		transferSubject.setSign("");
		transferSubject.setVersion("1.0");
		
		log.info("美的盘点出入库反馈：查询盘点出入库表，");
		CheckInOrOut checkInOrOut = mdCheckInOrOutDao.findByBillCode(billCode);
		if(checkInOrOut == null ){
			log.info("美的盘点出入库反馈：不需要回传md");
			return;
		}
		OrderConfirmRequestBody orderConfirmRequestBody = new OrderConfirmRequestBody();
		
		orderConfirmRequestBody.setCustOrdNo(checkInOrOut.getMdOrderNo());
		orderConfirmRequestBody.setWhCode(checkInOrOut.getWhcode());
		orderConfirmRequestBody.setWhName("");
		orderConfirmRequestBody.setCustCustomerCode(checkInOrOut.getCustCustomerCode());
		orderConfirmRequestBody.setOrderType(checkInOrOut.getOrderType());
		orderConfirmRequestBody.setProcessTime(new Date());
		
		log.info("美的盘点出入库反馈：查询盘点出入库明细表，");
		List<CheckInOrOutItem> checkInOrOutItems = mdCheckInOrOutItemDao.findByBillCode(billCode);
		
		List<OrderConfirmDetail> ocdList = new ArrayList<OrderConfirmDetail>();
		if(checkInOrOutItems!=null){
			for(CheckInOrOutItem item:checkInOrOutItems){
				OrderConfirmDetail ocd = new OrderConfirmDetail();
				ocd.setCustGoodsCode(item.getCustGoodsCode());
				ocd.setLineNo(item.getLineNo());
				ocd.setPlanQty(item.getPlanQty());
				ocd.setQty(item.getQty());
				ocd.setGoodsStatus(item.getGoodsStatus());
				ocdList.add(ocd);
			}
		}
		orderConfirmRequestBody.setConfigDetails(ocdList);
		
		log.info("美的盘点出入库反馈：设置xml映射类值，");
		
		transferData.setTransferSubject(transferSubject);
		TransferBody transferBody = new TransferBody();
		transferBody.setContent(orderConfirmRequestBody);
		transferData.setTransferBody(transferBody);
		
		log.info("美的盘点出入库反馈：xml映射类转换xml，");
		ByteArrayOutputStream bais = new ByteArrayOutputStream(1024);
		JAXB.marshal(transferData, bais);
		
		StringWriter writer = new StringWriter();
		JAXB.marshal(transferData,writer);
		log.info("美的盘点出入库反馈：发送报文:"+writer.toString());
		
		
		checkInOrOut.setStatus("finish");
		this.mdCheckInOrOutDao.save(checkInOrOut);
		
		log.info("美的盘点出入库反馈：开始发送反馈消息，");
		Response response = sendOutMessage(bais);
		com.topisv.tms.rest.entity.md.response.Response mdResponse = JAXB.unmarshal(response.returnContent().asStream(), com.topisv.tms.rest.entity.md.response.Response.class);
		if (mdResponse.isFlag()) {
			log.info("美的盘点出入库反馈消息发送完成 结果成功"+mdResponse);
		}else {
			log.info("美的盘点出入库反馈消息发送完成 结果异常"+mdResponse);
			throw new PaiUException(ErrorCode.CHECK_BACK_INFO_ERROR);
		}
		StringWriter writerResop = new StringWriter();
		JAXB.marshal(mdResponse,writerResop);
		log.info("美的盘点出入库反馈：响应报文:"+writerResop.toString());
		
		log.info("美的盘点出入库反馈：end，");
	}
	
	public void cancelCheckInOrOut(String ordeno,String customerCode)throws Exception {
		log.info("美的盘点出入库取消：start，order:"+ordeno+" customerCode:"+customerCode);
		CheckInOrOut checkInOrOut = this.mdCheckInOrOutDao.findByMdOrderNoAndCustCustomerCode(ordeno,customerCode);
		ReverseBill reverseBill = this.reverseBillDao.loadByCode(checkInOrOut.getBillCode());
		if("finish".equals(checkInOrOut.getStatus())||"finish".equals(reverseBill.getStatus())) {
			log.info("美的盘点出入库取消：order:"+ordeno+" 改单已经完成 取消失败");
			throw new PaiUException(ErrorCode.CHECK_FNISH_CANCEL_ERROR);
		}
		log.info("美的盘点出入库取消：修改盘点入库状态");
		checkInOrOut.setStatus("cancel");
		this.mdCheckInOrOutDao.save(checkInOrOut);
		
		log.info("美的盘点出入库取消：删除冲正表");
		this.reverseBillDao.delete(reverseBill);
		
		log.info("美的盘点出入库取消：删除冲正明细表");
		List<ReverseBillItem> reverseBillItemList = this.reverseBillItemDao.loadByBillCode(checkInOrOut.getBillCode());
		for(ReverseBillItem item:reverseBillItemList){
			if("done".equals(item.getStatus())){
				log.info("美的盘点出入库取消：order:"+ordeno+" 改单已经开始 取消失败");
				throw new PaiUException(ErrorCode.CHECK_DOING_CANCEL_ERROR);
			}
		}
		this.reverseBillItemDao.delete(reverseBillItemList);
		
		log.info("美的盘点出入库取消：end，");
	}
	
	public EdiGoodsSku getEdiGoodsBar(String customerCode,String bar,Map<String,EdiGoodsSku> cacheSku){
		EdiGoodsSku ediGoodsSku = null;
		if(cacheSku.get(customerCode+"_"+bar) != null){
			ediGoodsSku = cacheSku.get(customerCode+"_"+bar);
		}else {
			ediGoodsSku = ediGoodsSkuDao.findByCustomerCodeAndBar(customerCode, bar);
		}
		return ediGoodsSku;
	}
	
	
	
	private Response sendOutMessage(ByteArrayOutputStream bais) throws Exception{
		String token = new StringBuilder().append(MDParam.USERNAME).append(":").append(MDParam.PASSWORD).toString();
		return Request.Post(MDParam.URL).connectTimeout(10000)
				.addHeader("Authorization", new StringBuilder().append("Basic ").append(SystemUtil.getBASE64(token)).toString())
				.addHeader("Content-Type", "text/xml; charset=utf-8").bodyByteArray(bais.toByteArray()).execute();
	}
	
}
